package com.iwhalecloud.citybrain.flow.platform.manager.application.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.iwhalecloud.citybrain.flow.platform.manager.application.common.enums.TaskLinkStatusEnum;
import com.iwhalecloud.citybrain.flow.platform.manager.application.service.impl.task.SyncMultiInstanceProcessTaskProcessor;
import com.iwhalecloud.citybrain.flow.platform.manager.application.utils.ExpressionUtils;
import com.iwhalecloud.citybrain.flow.platform.manager.application.utils.SpringUtils;
import com.iwhalecloud.citybrain.flow.platform.manager.domain.enums.MultiInstanceKeyEnum;
import com.iwhalecloud.citybrain.flow.platform.manager.domain.enums.OneVoteVetoTypeEnum;
import com.iwhalecloud.citybrain.flow.platform.manager.domain.enums.TaskCompletedKeyEnum;
import com.iwhalecloud.citybrain.flow.platform.manager.domain.model.CompletionCondition;
import com.iwhalecloud.citybrain.flow.platform.manager.domain.model.OneVoteVetoType;
import com.iwhalecloud.citybrain.flow.platform.manager.domain.model.factory.NodeCompletionConditionFactory;
import com.iwhalecloud.citybrain.flow.platform.manager.domain.model.factory.NodeOneVoteVetoFactory;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.flowable.bpmn.model.FlowElement;
import org.flowable.bpmn.model.Task;
import org.flowable.engine.HistoryService;
import org.flowable.engine.RepositoryService;
import org.flowable.engine.RuntimeService;
import org.flowable.engine.common.impl.el.ExpressionManager;
import org.flowable.engine.delegate.DelegateExecution;
import org.flowable.engine.repository.ProcessDefinition;
import org.flowable.engine.runtime.Execution;
import org.flowable.engine.runtime.ProcessInstance;
import org.flowable.task.api.history.HistoricTaskInstance;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;


/**
 * @author liyang
 * @version 1.0
 * @date 2021-07-17 18:31:42
 **/
@Slf4j
@Service(value = "multiInstanceCompleteHandler")
public class MultiInstanceCompleteHandler implements Serializable {


    @Autowired
    private RuntimeService runtimeService;

    @Autowired
    private RepositoryService repositoryService;

    @Autowired
    private NodeCompletionConditionFactory nodeCompletionConditionFactory;

    @Autowired
    private NodeOneVoteVetoFactory nodeOneVoteVetoFactory;

    public boolean accessCondition(DelegateExecution delegateExecution){

        String processInstanceId = delegateExecution.getProcessInstanceId();
        ProcessInstance processInstance = runtimeService.createProcessInstanceQuery().processInstanceId(processInstanceId).singleResult();
        if (processInstance.isSuspended()){
            return false;
        }

        String processDefinitionId = processInstance.getProcessDefinitionId();
        ProcessDefinition processDefinition = repositoryService.getProcessDefinition(processDefinitionId);
        String deploymentId = processDefinition.getDeploymentId();

        Object object = delegateExecution.getVariable(TaskCompletedKeyEnum.APPROVAL.getCode());

        //获取当前实例的审批结果
        //如果是拒绝，则判断是否有一票否决的配置
        if (!Objects.equals(object,TaskCompletedKeyEnum.PASS.getCode())){

            //查询是否有一票否决的配置
            List<OneVoteVetoType> oneVoteVetoTypeList = nodeOneVoteVetoFactory.getOneVoteVetos(deploymentId,delegateExecution.getCurrentActivityId());
            //如果配置的有一票否决，则判断是否满足一票否决的条件
            if (Objects.nonNull(oneVoteVetoTypeList) && oneVoteVetoTypeList.size() > 0){
                String oneVoteVetoType = oneVoteVetoTypeList.get(0).getValue();
                if (OneVoteVetoTypeEnum.ONE_VOTE_VETO_EVERY_ONE.getCode().equals(oneVoteVetoType)){
                    delegateExecution.setVariable(TaskCompletedKeyEnum.APPROVAL.getCode(), TaskCompletedKeyEnum.REJECT.getCode());
                    // 获取子流程数据并同步给待办组件
                    this.checkSyncDataByScene(delegateExecution);
                    return true;
                }
            }
        }

        //没有一票否决，就走普通的判断逻辑
        return checkCompleteCondition(delegateExecution,deploymentId);

    }

    public boolean checkCompleteCondition(DelegateExecution delegateExecution,String deploymentId){

        //节点编码
        String nodeCode = delegateExecution.getCurrentActivityId();

        //完成条件，新的流程图的完成条件配置在表格中，老的在流程图中
        List<CompletionCondition> completionConditionList = nodeCompletionConditionFactory.getCompletionConditons(deploymentId,nodeCode);

        //modelCustomConfigList 为空，说明是老的流程图，完成条件配置在userTask里面
        if (Objects.isNull(completionConditionList) || completionConditionList.size() == 0){

            FlowElement flowElement = delegateExecution.getCurrentFlowElement();
            //如果是TASK
            if (flowElement instanceof Task){
                Task task = (Task) flowElement;
                String completionCondition = task.getLoopCharacteristics().getCompletionCondition();
                return getCompletionResult(delegateExecution,completionCondition);
            }
            return false;
        }else{
            //新的流程图，完成条件配置在表格中
            CompletionCondition completionCondition = completionConditionList.get(0);
            String completionConditionStr = completionCondition.getValue();
            return getCompletionResult(delegateExecution,  completionConditionStr);

        }
    }

    private boolean getCompletionResult(DelegateExecution delegateExecution, String completionCondition) {
        ExpressionManager expressionManager = ExpressionUtils.getExpressionManager();
        int nrOfCompletedInstances = (int) delegateExecution.getVariable(MultiInstanceKeyEnum.NUMBER_OF_COMPLETED_INSTANCES.getCode());
        int nrOfInstances = (int) delegateExecution.getVariable(MultiInstanceKeyEnum.NUMBER_OF_INSTANCES.getCode());

        boolean result = (boolean) expressionManager.createExpression(completionCondition).getValue(delegateExecution);

        //已达到完成条件
        if (result){
            delegateExecution.setVariable(TaskCompletedKeyEnum.APPROVAL.getCode(), TaskCompletedKeyEnum.PASS.getCode());
            return true;
        }

        //完成条件为false，但是完成的数量已经超过了会签数量
        //完成的数量 = 通过的数量 + 不通过的数量
        //如果完成数量大于会签数量，则表明会签节点结束
        if (nrOfCompletedInstances >= nrOfInstances){
            //如果不包含斜杠，则说明是按照完成人数来计算的
            if (!completionCondition.contains("/")){
                //统计完成的人数是否大于等于已经审批的人数，如果是，则认为审批通过
                Object nrOfPassInstancesObj = delegateExecution.getVariable(MultiInstanceKeyEnum.NUMBER_OF_PASS_INSTANCES.getCode());
                if (Objects.isNull(nrOfPassInstancesObj) || ((int)nrOfPassInstancesObj) >= nrOfCompletedInstances){
                    delegateExecution.setVariable(TaskCompletedKeyEnum.APPROVAL.getCode(), TaskCompletedKeyEnum.PASS.getCode());
                    return true;
                }
            }
            delegateExecution.setVariable(TaskCompletedKeyEnum.APPROVAL.getCode(), TaskCompletedKeyEnum.REJECT.getCode());
            return true;
        }
        return false;
    }


    /**
     * 获取子流程数据并同步给待办组件
     *
     * @param execution
     */
    private void checkSyncDataByScene(DelegateExecution execution) {
        if(execution == null) {
            return;
        }
        try {
            // 流程实例
            String processInstanceId = execution.getProcessInstanceId();
            // 根据流程实例获取子流程的Executions
            RuntimeService runtimeService = SpringUtils.getBean(RuntimeService.class);
            List<Execution> childExecutionList = runtimeService.createExecutionQuery().processInstanceId(processInstanceId).onlyChildExecutions().list();
            log.info("childExecutionLists:" + JSONObject.toJSONString(childExecutionList));
            // 根据流程实例查询到历史的
            HistoryService historyService = SpringUtils.getBean(HistoryService.class);
            // 查询历史任务列表
            List<HistoricTaskInstance> historicTaskInstances = historyService.createHistoricTaskInstanceQuery().processInstanceId(processInstanceId).list();
            if(CollectionUtils.isNotEmpty(historicTaskInstances)) {
                List<String> filterTaskIds = historicTaskInstances.stream().filter(x -> childExecutionList.stream().map(y -> y.getId()).collect(Collectors.toList()).contains(x.getExecutionId())).map(x -> x.getId()).collect(Collectors.toList());
                log.info("filterTaskIds:" + JSONObject.toJSONString(filterTaskIds));
                // 不为空,同步待办组件
                if(CollectionUtils.isNotEmpty(filterTaskIds)) {
                    // 更新会签子流程任务
                    List<String> taskIds = new ArrayList<>();
                    taskIds.addAll(filterTaskIds);
                    SyncMultiInstanceProcessTaskProcessor processTaskProcessor = SpringUtils.getBean(SyncMultiInstanceProcessTaskProcessor.class);
                    processTaskProcessor.syncDataByScene(null, taskIds, null, TaskLinkStatusEnum.DONE.getCode(),false);
                }
            }
        } catch (Exception ex) {
            log.error("获取子流程的Execution集合失败,流程实例ID:["+ execution.getProcessInstanceId() +"],失败原因：{}", ex.getMessage(), ex);
        }
    }

}
